﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using iTransact.Helpers;

namespace iTransact.Requests
{
	public class Request
	{
		public Request()
		{
			OrderItems = new List<OrderItem>();
			MetaData = new Dictionary<string, string>();
			Description = "Transasction from Web on " + DateTime.Now;
			Errors = new List<Error>();
			TestMode = false;
		}

		[Required]
		public decimal Total { get; set; }

		[Required]
		public string CreditCardNumber { get; set; }

		[Required]
		public string ExpirationMonth { get; set; }

		[Required]
		public string ExpirationYear { get; set; }

		[Required]
		public string Cvv { get; set; }

		[Required]
		public string BillingZip { get; set; }

		[Required]
		public string BillingPhone { get; set; }

		[Required]
		public string Email { get; set; }

		[Required]
		public string Description { get; set; }

		[Required]
		public string iTransactUserName { get; set; }

		[Required]
		public string iTransactApiKey { get; set; }
		
		[Required]
		public string iTransactGateway { get; set; }

		public bool TestMode { get; set; }

		// Optional Fields
		public string BillingAddress { get; set; }
		public string BillingAddress2 { get; set; }
		public string BillingCity { get; set; }
		public string BillingState { get; set; }
		public string BillingFirstName { get; set; }
		public string BillingLastName { get; set; }
		public string BillingCountry { get; set; }

		//Optional Shipping Informatoin
		public string ShippingAddress { get; set; }
		public string ShipingAddress2 { get; set; }
		public string ShippingCity { get; set; }
		public string ShippingState { get; set; }
		public string ShippingZip { get; set; }
		public string ShippingFirstName { get; set; }
		public string ShippingLastName { get; set; }
		public string ShippingCountry { get; set; }
		public string ShippingPhone { get; set; }

		public string CustomerId { get; set; }

		public string PreAuth { get; set; }
		public string AuthCode { get; set; }

		/// <summary>
		/// You must either supply a list of OrderItems or a Total
		/// </summary>
		public IList<OrderItem> OrderItems { get; set; }

		/// <summary>
		/// Key/Value pair data that will be saved on the server that you can query later inside of iTransat.
		/// </summary>
		public IDictionary<string, string> MetaData { get; set; }

		/// <summary>
		/// Captures Errors generated from the Request
		/// </summary>
		public List<Error> Errors { get; private set; }

		#region Validation
		
		public bool IsValid
		{
			get
			{
				Errors = Validate().ToList();
				return Errors.Count == 0;
			}
		}
		
		/// <summary>
		/// Perform Validation
		/// </summary>
		/// <returns></returns>
		private IEnumerable<Error> Validate()
		{
			// Check against data annotations
			foreach (var error in DataAnnotationsValidationRunner.GetErrors(this))
				yield return error;


			if (OrderItems.Count == 0 && !TotalIsGreaterThanZero())
			{
				yield return new Error("Total or OrderItems", "You must supply order items or Total that is greater than 0");
			}

			if (OrderItems.Count() == 0)
			{
				if (!TotalIsGreaterThanZero())
					yield return new Error("Total", "Total must be greater than 0.");
			}

			if (!CreditCardNumberValidAndNotEmpty())
				yield return new Error("CreditCardNumber", "Credit Card Number can't be empty.");

			if (!ExpirationMonthIsNotEmpty())
				yield return new Error("ExpirationMonth", "Expiration Month is required.");

			if (!ExpirationYearIsNotEmpty())
				yield return new Error("ExpirationYear", "Expiration Year is required.");

			
		}

		bool TotalIsGreaterThanZero()
		{
			return Total > 0;
		}

		bool CreditCardNumberValidAndNotEmpty()
		{
			return !string.IsNullOrEmpty(CreditCardNumber);
		}

		bool ExpirationMonthIsNotEmpty()
		{
			return !string.IsNullOrEmpty(ExpirationMonth);
		}

		bool ExpirationYearIsNotEmpty()
		{
			return !string.IsNullOrEmpty(ExpirationMonth);
		}

		#endregion

	}
}